﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Controls.Primitives;

namespace ComboBoxExample
{
    [TemplateVisualState(Name = StateNormal, GroupName = GroupCommonStates)]
    [TemplateVisualState(Name = StateMouseOver, GroupName = GroupCommonStates)]
    [TemplateVisualState(Name = StatePressed, GroupName = GroupCommonStates)]
    [TemplateVisualState(Name = StateDisabled, GroupName = GroupCommonStates)]
    [TemplateVisualState(Name = StateUnfocused, GroupName = GroupFocusStates)]
    [TemplateVisualState(Name = StateFocused, GroupName = GroupFocusStates)]
    [TemplatePart(Name = Part_LayoutRoot, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = Part_DropDownButton, Type = typeof(Button))]
    [TemplatePart(Name = Part_ScrollViewer, Type = typeof(ScrollViewer))]
    [TemplatePart(Name = Part_EntryTextBox, Type = typeof(TextBox))]
    public class WP7ComboBox : ItemsControl
    {
        public event SelectionChangedEventHandler SelectionChanged;
        public event RoutedEventHandler Click;

        private const string GroupCommonStates = "CommonStates";
        private const string StateNormal = "Normal";
        private const string StateMouseOver = "MouseOver";
        private const string StatePressed = "Pressed";
        private const string StateDisabled = "Disabled";
        private const string GroupFocusStates = "FocusStates";
        private const string StateUnfocused = "Unfocused";
        private const string StateFocused = "Focused";
        private const string Part_LayoutRoot = "LayoutRoot";
        private const string Part_DropDownButton = "DropDownButton";
        private const string Part_EntryTextBox = "EntryTextBox";
        private const string Part_ScrollViewer = "ScrollViewer";

        public static readonly DependencyProperty IsSelectionActiveProperty = DependencyProperty.RegisterAttached("IsSelectionActive", typeof(bool), typeof(WP7ComboBox), new PropertyMetadata(OnIsSelectionActiveChanged));
        public static readonly DependencyProperty ClickModeProperty = DependencyProperty.Register("ClickMode", typeof(ClickMode), typeof(WP7ComboBox), new PropertyMetadata(OnClickModePropertyChanged));
        public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.Register("IsFocused", typeof(bool), typeof(WP7ComboBox), null);
        public static readonly DependencyProperty IsDroppedDownProperty = DependencyProperty.Register("IsDroppedDown", typeof(bool), typeof(WP7ComboBox), new PropertyMetadata(OnIsDroppedDown));
        public static readonly DependencyProperty IsPressedProperty = DependencyProperty.Register("IsPressed", typeof(bool), typeof(WP7ComboBox), new PropertyMetadata(OnIsPressedPropertyChanged));
        public new static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register("IsEnabled", typeof(bool), typeof(WP7ComboBox), new PropertyMetadata(OnIsEnabledPropertyChanged));
        public static readonly DependencyProperty FocusBorderColorProperty = DependencyProperty.Register("FocusBorderColor", typeof(Brush), typeof(WP7ComboBox), null);
        public static readonly DependencyProperty ItemContainerStyleProperty = DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(WP7ComboBox), new PropertyMetadata(OnItemContainerStyleChanged));
        public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register("SelectedIndex", typeof(int), typeof(WP7ComboBox), new PropertyMetadata(OnSelectedIndexChanged));
        public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(WP7ComboBox), new PropertyMetadata(OnSelectedItemChanged));
        public static readonly DependencyProperty DropDownHeightProperty = DependencyProperty.Register("DropDownHeight", typeof(double), typeof(WP7ComboBox), null);
        public static readonly DependencyProperty DropDownWidthProperty = DependencyProperty.Register("DropDownWidth", typeof(double), typeof(WP7ComboBox), null);
        public static readonly DependencyProperty DisplayMemberBindingProperty = DependencyProperty.Register("DisplayMemberBinding", typeof(Binding), typeof(WP7ComboBox), null);

        private readonly TextBox _textBoxForBindingText = new TextBox();
        private static readonly Point _Zero = new Point(0.0, 0.0);
        private static int _preDroppedDownSelectedIndex = -1;
        private bool _applyFilter;
        private bool _isCtrl;
        private WP7ComboBoxItem _comboBoxItemOldFocus;
        private Grid _layoutRoot;
        private TextBox _txtBoxEntry;
        private Button _btnDropDown;
        private bool _isMouseCaptured;
        private Dictionary<object, WP7ComboBoxItem> _objectToComboBoxItem;
        private Point _mousePosition;
        private bool _suspendStateChanges;
        private bool _isMouseLeftButtonDown;
        private WP7ComboBoxItem _tabOnceActiveElement;
        private bool _processingSelectionPropertyChange;
        private static Popup _popupContainer;

        public WP7ComboBox()
        {
            DefaultStyleKey = typeof(WP7ComboBox);
            this.IsTabStop = true;
            this.Loaded += this.OnLoaded;
            this.GotFocus += this.OnGotFocus;
            this.LostFocus += this.OnLostFocus;
            this.KeyDown += this.OnKeyDown;
            this.KeyUp += this.OnKeyUp;
            this.MouseLeftButtonDown += this.OnMouseLeftButtonDown;
            this.MouseLeftButtonUp += this.OnMouseLeftButtonUp;
            this.IsEnabled = true;
            this.SelectedIndex = -1;
            this.DropDownHeight = 150;
            this.DropDownWidth = 0;
            ScrollViewer.SetHorizontalScrollBarVisibility(this, ScrollBarVisibility.Auto);
            ScrollViewer.SetVerticalScrollBarVisibility(this, ScrollBarVisibility.Auto);
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            this.UpdateVisualState(false);
        }

        internal void OnGotFocus(object sender, RoutedEventArgs e)
        {
            this.IsFocused = true;
            this.OnGotFocus(e);

            if (this._txtBoxEntry != null)
                this._txtBoxEntry.Dispatcher.BeginInvoke(() => this._txtBoxEntry.Select(0, int.MaxValue));
        }

        protected new void OnGotFocus(RoutedEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            this.UpdateVisualState();
        }

        internal void OnLostFocus(object sender, RoutedEventArgs e)
        {
            this.IsFocused = false;
            this.OnLostFocus(e);
        }

        protected new void OnLostFocus(RoutedEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            this._suspendStateChanges = true;
            try
            {
                if (this.ClickMode != ClickMode.Hover)
                {
                    this.IsPressed = false;
                }
            }
            finally
            {
                this._suspendStateChanges = false;
                WP7ComboBoxItem comboBoxItem = FocusManager.GetFocusedElement() as WP7ComboBoxItem;
                if (comboBoxItem == null || (comboBoxItem.ParentComboBox != this))
                    this.IsDroppedDown = false;

                this.UpdateVisualState();
            }
        }

        private static bool IsVerticalOrientation()
        {
            return true;
        }

        public static bool GetIsSelectionActive(DependencyObject element)
        {
            if (element == null)
                throw new ArgumentNullException("element");

            return (bool)element.GetValue(IsSelectionActiveProperty);
        }

        private WP7ComboBoxItem GetComboBoxItemForObject(object value)
        {
            WP7ComboBoxItem item = value as WP7ComboBoxItem;
            if (item == null)
                this.ObjectToComboBoxItem.TryGetValue(value, out item);

            return item;
        }

        private IDictionary<object, WP7ComboBoxItem> ObjectToComboBoxItem
        {
            get
            {
                if (this._objectToComboBoxItem == null)
                    this._objectToComboBoxItem = new Dictionary<object, WP7ComboBoxItem>();

                return this._objectToComboBoxItem;
            }
        }

        private void OnEntryTextChanged(object sender, TextChangedEventArgs e)
        {
            this.ApplyFilter();
        }

        private void OnDropDownClick(object sender, RoutedEventArgs e)
        {
            this.IsDroppedDown = !this.IsDroppedDown;
        }

        protected virtual void OnIsPressedChanged(DependencyPropertyChangedEventArgs e)
        {
            this.UpdateVisualState();
        }

        private static void OnIsPressedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WP7ComboBox)d).OnIsPressedChanged(e);
        }

        protected new void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            if (!e.Handled && (this.IsEnabled && (this.ClickMode != ClickMode.Hover)))
            {
                e.Handled = true;
                this._suspendStateChanges = true;
                try
                {
                    Focus();
                    if (this._isMouseCaptured)
                        this.IsPressed = true;
                }
                finally
                {
                    this._suspendStateChanges = false;
                    this.UpdateVisualState();
                }

                if (this.ClickMode == ClickMode.Press)
                    this.OnClick();
            }
        }

        internal void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this._isMouseLeftButtonDown = true;
            this.OnMouseLeftButtonDown(e);
        }

        protected new void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            if (!e.Handled && (this.IsEnabled && (this.ClickMode != ClickMode.Hover)))
            {
                e.Handled = true;
                if (this.ClickMode == ClickMode.Release)
                    this.OnClick();

                this.ReleaseMouseCaptureInternal();
                this.IsPressed = false;
            }
        }

        internal void ReleaseMouseCaptureInternal()
        {
            this.ReleaseMouseCapture();
            this._isMouseCaptured = false;
        }

        internal void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            this._isMouseLeftButtonDown = false;
            this.OnMouseLeftButtonUp(e);
        }

        internal virtual void OnSelectedIndexChanged(int oldValue, int newValue)
        {
            object obj2 = ((-1 != oldValue) && (oldValue < this.Items.Count)) ? this.Items[oldValue] : null;
            object obj3 = (-1 != newValue) ? this.Items[newValue] : null;
            this.ProcessSelectionPropertyChange(SelectedIndexProperty, obj2, obj3);
        }

        private static void OnSelectedIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WP7ComboBox)d).OnSelectedIndexChanged((int)e.OldValue, (int)e.NewValue);
        }

        internal virtual void OnSelectedItemChanged(object oldValue, object newValue)
        {
            this.ProcessSelectionPropertyChange(SelectedItemProperty, oldValue, newValue);
        }

        private void ProcessSelectionPropertyChange(DependencyProperty changedProperty, object oldValue, object newValue)
        {
            if (this._processingSelectionPropertyChange)
                return;

            try
            {
                this._processingSelectionPropertyChange = true;
                List<object> removedItems = new List<object>();
                List<object> addedItems = new List<object>();
                if (oldValue != null)
                {
                    WP7ComboBoxItem comboBoxItemForObject = this.GetComboBoxItemForObject(oldValue);
                    if (comboBoxItemForObject != null)
                        comboBoxItemForObject.IsSelected = false;

                    removedItems.Add(oldValue);
                }

                object obj2 = null;
                int index = -1;

                if (newValue != null)
                {
                    WP7ComboBoxItem comboBoxItem = this.GetComboBoxItemForObject(newValue);
                    if (comboBoxItem != null)
                        comboBoxItem.IsSelected = true;

                    obj2 = newValue;
                    index = Items.IndexOf(obj2);
                    addedItems.Add(newValue);

                    if ((comboBoxItem != null) && (this._txtBoxEntry != null))
                        this._txtBoxEntry.Text = this.GetComboBoxItemText(comboBoxItem);

                    this.ScrollIntoView(newValue);
                }

                if (SelectedIndexProperty != changedProperty)
                    this.SelectedIndex = index;

                if (SelectedItemProperty != changedProperty)
                    this.SelectedItem = obj2;

                this.OnSelectionChanged(new SelectionChangedEventArgs(removedItems, addedItems));
            }
            finally
            {
                this._processingSelectionPropertyChange = false;
            }
        }

        internal virtual void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            SelectionChangedEventHandler selectionChanged = this.SelectionChanged;
            if (selectionChanged != null)
                selectionChanged(this, e);
        }

        private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WP7ComboBox)d).OnSelectedItemChanged(e.OldValue, e.NewValue);
        }

        protected virtual void OnClick()
        {
            RoutedEventHandler click = this.Click;
            if (click != null)
            {
                RoutedEventArgs e = new RoutedEventArgs();
                click(this, e);
            }
        }

        internal void OnClickInternal()
        {
            this.OnClick();
        }

        private static void OnClickModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ClickMode newValue = (ClickMode)e.NewValue;
            if (((newValue != ClickMode.Release) && (newValue != ClickMode.Press)) && (newValue != ClickMode.Hover))
                throw new ArgumentException("Invalid Value");
        }

        private T Get<T>(string partName) where T : FrameworkElement
        {
            return this.GetTemplateChild(partName) as T;
        }

        private static void OnIsSelectionActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WP7ComboBox)d).OnIsSelectionActiveChanged((bool)e.OldValue, (bool)e.NewValue);
        }

        internal virtual void OnIsSelectionActiveChanged(bool oldValue, bool newValue)
        {
            if (this.SelectedItem == null)
                return;

            WP7ComboBoxItem comboBoxItemForObject = this.GetComboBoxItemForObject(this.SelectedItem);
            if (comboBoxItemForObject != null)
                comboBoxItemForObject.ChangeVisualState();
        }

        private static void OnIsEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            WP7ComboBox comboBox = d as WP7ComboBox;
            bool newValue = (bool)e.NewValue;
            if (comboBox != null) comboBox.OnIsEnabledChanged(newValue);
        }

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            WP7ComboBoxItem comboBoxItem = element as WP7ComboBoxItem;
            if (comboBoxItem == null)
                return;

            comboBoxItem.ParentComboBox = this;
            bool flag = true;
            if (comboBoxItem != item)
            {
                if (ItemTemplate != null)
                {
                    comboBoxItem.ContentTemplate = this.ItemTemplate;
                }
                else if (!string.IsNullOrEmpty(this.DisplayMemberPath))
                {
                    Binding binding = new Binding(this.DisplayMemberPath);
                    comboBoxItem.SetBinding(ContentControl.ContentProperty, binding);
                    flag = false;
                }

                comboBoxItem.Item = item;
                if (flag)
                    comboBoxItem.Content = item;

                this.ObjectToComboBoxItem[item] = comboBoxItem;
            }

            if ((this.ItemContainerStyle != null) && (comboBoxItem.Style == null))
                comboBoxItem.Style = this.ItemContainerStyle;

            if (comboBoxItem.IsSelected)
            {
                this.SelectedItem = comboBoxItem.Item ?? comboBoxItem;
            }
            else if ((-1 != this.SelectedIndex) && (this.Items.IndexOf(this.SelectedItem) != this.SelectedIndex))
            {
                try
                {
                    this._processingSelectionPropertyChange = true;
                    this.SelectedIndex = this.Items.IndexOf(this.SelectedItem);
                }
                finally
                {
                    this._processingSelectionPropertyChange = false;
                }
            }
        }

        protected override void ClearContainerForItemOverride(DependencyObject element, object item)
        {
            base.ClearContainerForItemOverride(element, item);
            WP7ComboBoxItem item2 = element as WP7ComboBoxItem;
            if (item2 == null)
                return;

            if (item == null)
                item = item2.Item ?? item2;

            if ((item2.Item ?? item2) == this.SelectedItem)
                this.SelectedItem = null;

            item2.IsSelected = false;
            item2.ParentComboBox = null;
            if (item2 != item)
                this.ObjectToComboBoxItem.Remove(item);
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            WP7ComboBoxItem item = new WP7ComboBoxItem();
            if (this.ItemContainerStyle != null)
                item.Style = this.ItemContainerStyle;

            return item;
        }

        private void ResetFilter()
        {
            foreach (object item in Items)
                this.GetComboBoxItemForObject(item).Visibility = Visibility.Visible;
        }

        private void ApplyFilter()
        {
            if (!this._applyFilter || (this._txtBoxEntry == null) || !this.IsDroppedDown)
                return;

            string prefixFilter = this._txtBoxEntry.Text;
            bool forceVisible = string.IsNullOrEmpty(prefixFilter);
            foreach (object item in Items)
            {
                WP7ComboBoxItem comboBoxItem = this.GetComboBoxItemForObject(item);
                string text = this.GetComboBoxItemText(comboBoxItem);
                comboBoxItem.Visibility = (forceVisible || text.StartsWith(prefixFilter, StringComparison.InvariantCultureIgnoreCase))
                                                                    ? Visibility.Visible
                                                                    : Visibility.Collapsed;
            }
        }

        private string GetComboBoxItemText(ContentControl comboBoxItem)
        {
            if (comboBoxItem == null)
                return string.Empty;

            object content = comboBoxItem.Content;
            if (string.IsNullOrEmpty(DisplayMemberPath) && (this.DisplayMemberBinding == null))
            {
                TypeConverter typeConverter = TypeConverters.GetTypeConverterForType(content.GetType());
                return (typeConverter != null) ? typeConverter.ConvertToString(content) : content.ToString();
            }

            this._textBoxForBindingText.DataContext = content;
            return this._textBoxForBindingText.Text;
        }

        private void HideDropDown()
        {
            if (_popupContainer == null)
                return;

            if (this._txtBoxEntry != null)
                this._txtBoxEntry.Focus();

            _popupContainer.IsOpen = false;
            _popupContainer = null;
        }

        internal void NotifyComboBoxItemGotFocus(WP7ComboBoxItem comboBoxItemNewFocus)
        {
            if (((this._tabOnceActiveElement == null) || (this != this._tabOnceActiveElement.ParentComboBox)) && (1 <= Items.Count))
                this._tabOnceActiveElement = this.GetComboBoxItemForObject(this.Items[0]);

            if ((this._tabOnceActiveElement != null) && (comboBoxItemNewFocus != this._tabOnceActiveElement))
                this._tabOnceActiveElement.Focus();

            else
            {
                this.Items.IndexOf(comboBoxItemNewFocus.Item ?? comboBoxItemNewFocus);
                if (((this._comboBoxItemOldFocus != null)) && ((this == this._comboBoxItemOldFocus.ParentComboBox) && (comboBoxItemNewFocus != this._comboBoxItemOldFocus)))
                    this.SelectedItem = comboBoxItemNewFocus.Item ?? comboBoxItemNewFocus;

                this._comboBoxItemOldFocus = null;
            }
        }

        internal void NotifyListItemLostFocus(WP7ComboBoxItem comboBoxItemOldFocus)
        {
            this._comboBoxItemOldFocus = comboBoxItemOldFocus;
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this._layoutRoot = this.GetTemplateChild(Part_LayoutRoot) as Grid; //Get<Grid>(Part_LayoutRoot);
            if (this._layoutRoot == null)
                throw new ArgumentNullException(string.Format("You must provide a layout root named {0} when defining your style.", Part_LayoutRoot));

            this._txtBoxEntry = Get<TextBox>(Part_EntryTextBox);
            if (this._txtBoxEntry != null)
            {
                if (!string.IsNullOrEmpty(this.DisplayMemberPath))
                {
                    Binding binding = new Binding(this.DisplayMemberPath);
                    this._textBoxForBindingText.SetBinding(TextBox.TextProperty, binding);
                }
                else if (this.DisplayMemberBinding != null)
                {
                    this._textBoxForBindingText.SetBinding(TextBox.TextProperty, this.DisplayMemberBinding);
                }

                this.MeasureOverride(new Size(double.PositiveInfinity, double.PositiveInfinity));
                if (this.SelectedItem != null)
                {
                    WP7ComboBoxItem comboBoxItem = this.GetComboBoxItemForObject(this.SelectedItem);
                    comboBoxItem.IsSelected = true;
                    this._txtBoxEntry.Text = this.GetComboBoxItemText(comboBoxItem);
                }

                this._txtBoxEntry.TextChanged += OnEntryTextChanged;
            }

            this._btnDropDown = Get<Button>(Part_DropDownButton);
            if (this._btnDropDown != null)
                this._btnDropDown.Click += OnDropDownClick;

            this.ElementScrollViewer = Get<ScrollViewer>(Part_ScrollViewer);
            if (this.ElementScrollViewer == null)
                throw new ArgumentNullException(string.Format("You must provide a scroll viewer named {0} when defining your style.", Part_ScrollViewer));

            Panel scrollViewerParent = this.ElementScrollViewer.Parent as Panel;
            if (scrollViewerParent != null)
                scrollViewerParent.Visibility = Visibility.Collapsed;

            this.ElementScrollViewer.HorizontalScrollBarVisibility = ScrollViewer.GetHorizontalScrollBarVisibility(this);
            this.ElementScrollViewer.VerticalScrollBarVisibility = ScrollViewer.GetVerticalScrollBarVisibility(this);
        }

        private static void OnIsDroppedDown(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            WP7ComboBox comboBox = ((WP7ComboBox)d);

            if (comboBox.IsDroppedDown)
            {
                _preDroppedDownSelectedIndex = comboBox.SelectedIndex;
                comboBox.ShowDropDown();
            }
            else
            {
                comboBox.HideDropDown();
            }
        }

        protected new void OnKeyDown(KeyEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            this._applyFilter = true;
            if (char.IsLetterOrDigit((char)e.PlatformKeyCode))
            {
                if (!this.IsDroppedDown)
                    this.IsDroppedDown = true;

                e.Handled = false;
                return;
            }

            if (!e.Handled && this.OnKeyDownInternal(e.Key))
            {
                e.Handled = true;
                this._applyFilter = false;
            }
        }

        internal void OnKeyDown(object sender, KeyEventArgs e)
        {
            this.OnKeyDown(e);
        }

        internal virtual bool OnKeyDownInternal(Key key)
        {
            if (this.IsEnabled && (this.ClickMode != ClickMode.Hover))
            {
                switch (key)
                {
                    case Key.Ctrl:
                        this._isCtrl = true;
                        return false;

                    case Key.Escape:
                        if (this.IsDroppedDown)
                        {
                            this.IsDroppedDown = false;
                            this.SelectedIndex = _preDroppedDownSelectedIndex;
                        }
                        return true;

                    case Key.Down:
                        if (this._isCtrl)
                        {
                            this.IsDroppedDown = true;
                            return true;
                        }

                        this.PositionNext(1);
                        return true;

                    case Key.Up:
                        this.PositionPrevious(1);
                        return true;

                    default:
                        break;
                }
            }

            return false;
        }

        protected new void OnKeyUp(KeyEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            if (!e.Handled && this.OnKeyUpInternal(e.Key))
                e.Handled = true;
        }

        internal void OnKeyUp(object sender, KeyEventArgs e)
        {
            this.OnKeyUp(e);
        }

        internal bool OnKeyUpInternal(Key key)
        {
            if (key == Key.Ctrl)
            {
                this._isCtrl = false;
                return false;
            }

            const bool flag = false;
            if ((!IsEnabled || (this.ClickMode == ClickMode.Hover)) || (key != Key.Space))
                return flag;

            if (!this._isMouseLeftButtonDown)
            {
                this.ReleaseMouseCaptureInternal();
                if (this.IsPressed && (this.ClickMode == ClickMode.Release))
                    this.OnClick();

                this.IsPressed = false;
            }
            else if (this._isMouseCaptured)
            {
                bool flag2 = this.IsValidMousePosition();
                this.IsPressed = flag2;
                if (!flag2)
                    this.ReleaseMouseCaptureInternal();
            }

            return true;
        }

        internal bool IsValidMousePosition()
        {
            return ((((this._mousePosition.X >= 0.0) && (this._mousePosition.X <= this.ActualWidth)) &&
                      (this._mousePosition.Y >= 0.0)) && (this._mousePosition.Y <= this.ActualHeight));
        }

        private void ShowDropDown()
        {
            if (_popupContainer != null)
            {
                if (_popupContainer.Child == this.ElementScrollViewer)
                    return;

                HideDropDown();
            }

            MatrixTransform globalTransform = (MatrixTransform)this._layoutRoot.TransformToVisual(Application.Current.RootVisual);
            Point p = globalTransform.Matrix.Transform(_Zero);
            _popupContainer = new Popup();
            Panel parent = (Panel)this.ElementScrollViewer.Parent;
            parent.Children.Remove(this.ElementScrollViewer);
            _popupContainer.Child = this.ElementScrollViewer;
            double width = (this.DropDownWidth == 0.0) ? this._layoutRoot.ActualWidth : this.DropDownWidth;
            double height = this.DropDownHeight;

            if (width.Equals(double.NaN))
            {
                if (this.Items.Count == 0)
                    width = this._layoutRoot.ActualWidth;
            }

            this.ElementScrollViewer.MinWidth = 30.0;
            if (height < 100.0)
                height = 100.0;

            _popupContainer.Width = width;
            this.ElementScrollViewer.Width = width;
            _popupContainer.Height = height;
            this.ElementScrollViewer.Height = height;
            _popupContainer.HorizontalOffset = p.X;
            _popupContainer.VerticalOffset = p.Y + this._layoutRoot.ActualHeight;
            _popupContainer.Closed += delegate
            {
                ResetFilter();
                //parent.Children.Add(this.ElementScrollViewer);
            };
            _popupContainer.Opened += delegate
            {
                this.ApplyFilter();
                this.ScrollIntoView(this.SelectedItem);
                this.ElementScrollViewer.Height += 1;
                this.ElementScrollViewer.Measure(new Size(width, this.ElementScrollViewer.Height));
                this.ElementScrollViewer.Height -= 1;
                this.ElementScrollViewer.Measure(new Size(width, this.ElementScrollViewer.Height));
            };
            _popupContainer.IsOpen = true;
        }

        internal void UpdateVisualState()
        {
            this.UpdateVisualState(true);
        }

        internal void UpdateVisualState(bool useTransitions)
        {
            if (!this._suspendStateChanges)
                this.ChangeVisualState(useTransitions);
        }

        internal void NotifyListItemClicked(WP7ComboBoxItem comboBoxItem)
        {
            this._tabOnceActiveElement = comboBoxItem;
            if (comboBoxItem.IsSelected)
            {
                if (ModifierKeys.Control == (Keyboard.Modifiers & ModifierKeys.Control))
                    this.SetSelectedItem(null);
            }
            else
            {
                object item = comboBoxItem.Item ?? comboBoxItem;
                this.SetSelectedItem(item);
                if (this.IsDroppedDown)
                {
                    this.ScrollIntoView(item);
                    this.IsDroppedDown = false;
                }
            }
        }

        protected void OnIsEnabledChanged(bool isEnabled)
        {
            this._suspendStateChanges = true;
            try
            {
                if (!isEnabled)
                {
                    this.IsFocused = false;
                    this.IsPressed = false;
                    this._isMouseCaptured = false;
                    this._isMouseLeftButtonDown = false;
                }
            }
            finally
            {
                this._suspendStateChanges = false;
                this.UpdateVisualState();
            }
        }

        internal virtual void ChangeVisualState(bool useTransitions)
        {
            if (this.IsFocused && this.IsEnabled)
            {
                this.GoToState(useTransitions, new[] { StateFocused, StateUnfocused });
                return;
            }

            this.GoToState(useTransitions, new[] { StateUnfocused });

            if (!this.IsEnabled)
                this.GoToState(useTransitions, new[] { StateDisabled, StateNormal });

            else if (this.IsPressed)
                this.GoToState(useTransitions, new[] { StatePressed, StateMouseOver, StateNormal });

            else
                this.GoToState(useTransitions, new[] { StateNormal });
        }

        internal ScrollViewer ElementScrollViewer { get; set; }

        public void ScrollIntoView(object item)
        {
            Rect itemsHostRect;
            Rect listBoxItemRect;

            if (item == null)
                return;

            if (((this.ElementScrollViewer != null) && this.Items.Contains(item)) && !this.IsOnCurrentPage(item, out itemsHostRect, out listBoxItemRect))
            {
                if (IsVerticalOrientation())
                {
                    double verticalOffset = this.ElementScrollViewer.VerticalOffset;
                    double offset = 0.0;
                    if (itemsHostRect.Bottom < listBoxItemRect.Bottom)
                    {
                        offset = listBoxItemRect.Bottom - itemsHostRect.Bottom;
                        verticalOffset += offset;
                    }

                    if ((listBoxItemRect.Top - offset) < itemsHostRect.Top)
                    {
                        verticalOffset -= itemsHostRect.Top - (listBoxItemRect.Top - offset);
                    }

                    this.ElementScrollViewer.ScrollToVerticalOffset(verticalOffset);
                }
                else
                {
                    double horizontalOffset = this.ElementScrollViewer.HorizontalOffset;
                    double offset = 0.0;
                    if (itemsHostRect.Right < listBoxItemRect.Right)
                    {
                        offset = listBoxItemRect.Right - itemsHostRect.Right;
                        horizontalOffset += offset;
                    }

                    if ((listBoxItemRect.Left - offset) < itemsHostRect.Left)
                    {
                        horizontalOffset -= itemsHostRect.Left - (listBoxItemRect.Left - offset);
                    }

                    this.ElementScrollViewer.ScrollToHorizontalOffset(horizontalOffset);
                }
            }
        }

        private bool IsOnCurrentPage(object item, out Rect itemsHostRect, out Rect listBoxItemRect)
        {
            itemsHostRect = Rect.Empty;
            listBoxItemRect = Rect.Empty;

            if ((!this.IsDroppedDown || (this.ElementScrollViewer == null) || (this.ElementScrollViewer.RenderSize.Width == 0) || (this.ElementScrollViewer.RenderSize.Height == 0)))
                return true;

            WP7ComboBoxItem comboBoxItemForObject = this.GetComboBoxItemForObject(item);
            itemsHostRect = new Rect(new Point(), new Point(this.ElementScrollViewer.RenderSize.Width, this.ElementScrollViewer.RenderSize.Height));
            Thickness padding = this.ElementScrollViewer.Padding;
            itemsHostRect = new Rect(itemsHostRect.Left + padding.Left, itemsHostRect.Top + padding.Top, (itemsHostRect.Width - padding.Left) - padding.Right, (itemsHostRect.Height - padding.Top) - padding.Bottom);
            GeneralTransform transform = comboBoxItemForObject.TransformToVisual(ElementScrollViewer);
            listBoxItemRect = new Rect(transform.Transform(new Point()), transform.Transform(new Point(comboBoxItemForObject.RenderSize.Width, comboBoxItemForObject.RenderSize.Height)));

            if (!IsVerticalOrientation())
                return ((itemsHostRect.Left <= listBoxItemRect.Left) && (listBoxItemRect.Right <= itemsHostRect.Right));

            return ((itemsHostRect.Top <= listBoxItemRect.Top) && (listBoxItemRect.Bottom <= itemsHostRect.Bottom));
        }

        private void SetSelectedItem(object item)
        {
            this.SelectedItem = item;
            if (item == null)
                return;

            WP7ComboBoxItem comboBoxItem = item as WP7ComboBoxItem ?? this.ObjectToComboBoxItem[item];
            comboBoxItem.Focus();
        }

        internal void GoToState(bool useTransitions, params string[] stateNames)
        {
            if (stateNames == null) return;
            foreach (string stateName in stateNames)
            {
                if (VisualStateManager.GoToState(this, stateName, useTransitions))
                    return;
            }
        }
     
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return (item is WP7ComboBoxItem);
        }

        private void PositionNext(int visibleElementsToMove)
        {
            for (int index = this.SelectedIndex + 1; index < this.Items.Count; index++)
            {
                WP7ComboBoxItem comboBoxItem = this.GetComboBoxItemForObject(this.Items[index]);
                if (comboBoxItem.Visibility == Visibility.Visible)
                    visibleElementsToMove--;

                if (visibleElementsToMove == 0)
                {
                    this.SelectedIndex = index;
                    return;
                }
            }
        }

        private void PositionPrevious(int visibleElementsToMove)
        {
            for (int index = this.SelectedIndex - 1; index >= 0; index--)
            {
                WP7ComboBoxItem comboBoxItem = this.GetComboBoxItemForObject(this.Items[index]);
                if (comboBoxItem.Visibility == Visibility.Visible)
                    visibleElementsToMove--;

                if (visibleElementsToMove == 0)
                {
                    this.SelectedIndex = index;
                    return;
                }
            }
        }

        public ClickMode ClickMode
        {
            get { return (ClickMode)this.GetValue(ClickModeProperty); }
            set { this.SetValue(ClickModeProperty, value); }
        }

        public Style ItemContainerStyle
        {
            get { return (Style)this.GetValue(ItemContainerStyleProperty); }
            set { this.SetValue(ItemContainerStyleProperty, value); }
        }

        public Brush FocusBorderColor
        {
            get { return (Brush)this.GetValue(FocusBorderColorProperty); }
            internal set { this.SetValue(FocusBorderColorProperty, value); }
        }

        public bool IsPressed
        {
            get { return (bool)this.GetValue(IsPressedProperty); }
            protected internal set { this.SetValue(IsPressedProperty, value); }
        }

        public bool IsFocused
        {
            get { return (bool)this.GetValue(IsFocusedProperty); }
            internal set { this.SetValue(IsFocusedProperty, value); }
        }

        public new bool IsEnabled
        {
            get { return (bool)this.GetValue(IsEnabledProperty); }
            set { this.SetValue(IsEnabledProperty, value); }
        }

        public int SelectedIndex
        {
            get { return (int)this.GetValue(SelectedIndexProperty); }
            set { this.SetValue(SelectedIndexProperty, value); }
        }

        public bool IsDroppedDown
        {
            get { return (bool)this.GetValue(IsDroppedDownProperty); }
            set { this.SetValue(IsDroppedDownProperty, value); }
        }

        public object SelectedItem
        {
            get { return this.GetValue(SelectedItemProperty); }
            set { this.SetValue(SelectedItemProperty, value); }
        }

        public double DropDownHeight
        {
            get { return (double)this.GetValue(DropDownHeightProperty); }
            set { this.SetValue(DropDownHeightProperty, value); }
        }

        [TypeConverter(typeof(DoubleTypeConverter))]
        public double DropDownWidth
        {
            get { return (double)this.GetValue(DropDownWidthProperty); }
            set { this.SetValue(DropDownWidthProperty, value); }
        }

        public Binding DisplayMemberBinding
        {
            get { return (Binding)this.GetValue(DisplayMemberBindingProperty); }
            set { this.SetValue(DisplayMemberBindingProperty, value); }
        }

        private static void OnItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((WP7ComboBox)d).OnItemContainerStyleChanged((Style)e.OldValue, (Style)e.NewValue);
        }

        internal virtual void OnItemContainerStyleChanged(Style oldItemContainerStyle, Style newItemContainerStyle)
        {
            foreach (object item in Items)
            {
                WP7ComboBoxItem comboBoxItemForObject = this.GetComboBoxItemForObject(item);
                if ((comboBoxItemForObject != null) && ((comboBoxItemForObject.Style == null) || (oldItemContainerStyle == comboBoxItemForObject.Style)))
                {
                    if (comboBoxItemForObject.Style != null)
                        throw new NotSupportedException("ComboBox_OnItemContainerStyleChanged_CannotSetStyle");

                    comboBoxItemForObject.Style = newItemContainerStyle;
                }
            }
        }
    }

    public class TypeConverters
    {
        private static readonly Dictionary<Type, TypeConverter> _cachedTypeConverterForType = new Dictionary<Type, TypeConverter>();

        public static TypeConverter GetTypeConverterForType(Type propertyType)
        {
            TypeConverter typeConverterByName;
            if (!_cachedTypeConverterForType.TryGetValue(propertyType, out typeConverterByName))
            {
                object[] customAttributes = propertyType.GetCustomAttributes(typeof(TypeConverterAttribute), true);
                if ((customAttributes == null) || (customAttributes.Length <= 0))
                    return null;

                typeConverterByName = GetTypeConverterByName(((TypeConverterAttribute)customAttributes[0]).ConverterTypeName);
                _cachedTypeConverterForType[propertyType] = typeConverterByName;
            }

            return typeConverterByName;
        }

        private static TypeConverter GetTypeConverterByName(string converterTypeName)
        {
            return (Activator.CreateInstance(Type.GetType(converterTypeName)) as TypeConverter);
        }
    }

    public class DoubleTypeConverter : TypeConverter
    {
        public new bool CanConvertFrom(Type sourceType)
        {
            if (sourceType == typeof(string))
                return true;

            if (sourceType == typeof(double))
                return true;

            return false;
        }

        public new object ConvertFrom(object value)
        {
            if (value is string)
            {
                string strValue = (string)value;
                double dblValue;
                if (double.TryParse(strValue, out dblValue))
                    return dblValue;

                if (strValue.Equals("Auto", StringComparison.CurrentCultureIgnoreCase))
                    return double.NaN;
            }

            if (value is double)
                return value;

            return base.ConvertFrom(value);
        }
    }
}
